#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <tplayer.h>
#include <signal.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close

TPlayer * mTPlayer;
MediaInfo * mMediaInfo;

bool mPreparedFlag;
bool mLoopFlag;
bool mSetLoop;
bool mComplete;
bool mSeekable;

uint8_t bQuit = 0;

#define LCD_WIDTH 720.0
//#define LCD_WIDTH 480.0

/* Signal handler */
static void terminate(int sig_no)
{
    printf("Got signal %d, exiting ...\n", sig_no);

    if(mTPlayer != NULL) {
        TPlayerDestroy(mTPlayer);
        mTPlayer = NULL;
        printf("TPlayerDestroy() successfully\n");
    }
    printf("destroy tplayer \n");
    printf("tplaydemo exit\n");
    exit(0);
}

static void install_sig_handler(void)
{
    signal(SIGBUS, terminate);
    signal(SIGFPE, terminate);
    signal(SIGHUP, terminate);
    signal(SIGILL, terminate);
    signal(SIGINT, terminate);
    signal(SIGIOT, terminate);
    signal(SIGPIPE, terminate);
    signal(SIGQUIT, terminate);
    signal(SIGSEGV, terminate);
    signal(SIGSYS, terminate);
    signal(SIGTERM, terminate);
    signal(SIGTRAP, terminate);
    signal(SIGUSR1, terminate);
    signal(SIGUSR2, terminate);
}

//* a callback for tplayer.
int CallbackForTPlayer(void * pUserData, int msg, int param0, void * param1)
{
    CEDARX_UNUSE(param1);
    switch(msg) {
        case TPLAYER_NOTIFY_PREPARED: {
            printf("TPLAYER_NOTIFY_PREPARED,has prepared.\n");
            mPreparedFlag = 1;
            break;
        }

        case TPLAYER_NOTIFY_PLAYBACK_COMPLETE: {
            printf("TPLAYER_NOTIFY_PLAYBACK_COMPLETE\n");
            mComplete = 1;
            // PowerManagerReleaseWakeLock("tplayerdemo");
            break;
        }

        case TPLAYER_NOTIFY_SEEK_COMPLETE: {
            printf("TPLAYER_NOTIFY_SEEK_COMPLETE>>>>info: seek ok.\n");
            break;
        }

        case TPLAYER_NOTIFY_MEDIA_ERROR: {
            switch(param0) {
                case TPLAYER_MEDIA_ERROR_UNKNOWN: {
                    printf("erro type:TPLAYER_MEDIA_ERROR_UNKNOWN\n");
                    break;
                }
                case TPLAYER_MEDIA_ERROR_UNSUPPORTED: {
                    printf("erro type:TPLAYER_MEDIA_ERROR_UNSUPPORTED\n");
                    break;
                }
                case TPLAYER_MEDIA_ERROR_IO: {
                    printf("erro type:TPLAYER_MEDIA_ERROR_IO\n");
                    break;
                }
            }
            printf("TPLAYER_NOTIFY_MEDIA_ERROR\n");
            printf("error: open media source fail.\n");
            break;
        }

        case TPLAYER_NOTIFY_NOT_SEEKABLE: {
            mSeekable = 0;
            printf("info: media source is unseekable.\n");
            break;
        }

        case TPLAYER_NOTIFY_BUFFER_START: {
            printf("have no enough data to play\n");
            break;
        }

        case TPLAYER_NOTIFY_BUFFER_END: {
            printf("have enough data to play again\n");
            break;
        }

        case TPLAYER_NOTIFY_VIDEO_FRAME: {
            // printf("get the decoded video frame\n");
            break;
        }

        case TPLAYER_NOTIFY_AUDIO_FRAME: {
            // printf("get the decoded audio frame\n");
            break;
        }

        case TPLAYER_NOTIFY_SUBTITLE_FRAME: {
            // printf("get the decoded subtitle frame\n");
            break;
        }
        case TPLAYER_NOTYFY_DECODED_VIDEO_SIZE: {
            int w, h, y;
            w = ((int *)param1)[0]; // real decoded video width
            h = ((int *)param1)[1]; // real decoded video height
            printf("*****tplayerdemo:video decoded width = %d,height = %d\n", w, h);
            float divider = 1;
            if(w > LCD_WIDTH) {
                divider = w / LCD_WIDTH;
            }
            w = w / divider;
            h = h / divider;
            y = (LCD_WIDTH - h) / 2;
            printf("real set to display rect:w = %d,h = %d\n", w, h);
            TPlayerSetDisplayRect(mTPlayer, 0, y, w, h);
            break;
        }

        default: {
            //            printf("warning: unknown callback from Tinaplayer. %d\n", msg);
            break;
        }
    }
    return 0;
}

const int MAX_LENGTH = 128;
const int MAX_DATA   = 128;
static ssize_t read_data(const char * sysfs_path, char * data)
{
    ssize_t err = 0;
    FILE * fp   = NULL;
    fp          = fopen(sysfs_path, "r");
    if(fp) {
        err = fread(data, sizeof(char), MAX_DATA, fp);
        fclose(fp);
    }
    return err;
}

static ssize_t write_data(const char * sysfs_path, const char * data, size_t len)
{
    ssize_t err = 0;
    int fd      = -1;
    fd          = open(sysfs_path, O_WRONLY);
    if(fd) {
        errno = 0;
        err   = write(fd, data, len);
        if(err < 0) {
            err = -errno;
        }
        close(fd);
    } else {
        printf("%s: Failed to open file: %s error: %s", __FUNCTION__, sysfs_path, strerror(errno));
        err = -errno;
    }
    return err;
}

static void set_enhance_mode(void)
{
    char sysfs_path[MAX_LENGTH];
    char sysfs_data[MAX_DATA];
    unsigned int disp         = 0;
    unsigned int enhance_mode = 1;
    snprintf(sysfs_path, sizeof(sysfs_path), "sys/class/disp/disp/attr/disp");
    snprintf(sysfs_data, sizeof(sysfs_data), "%d", disp);
    write_data(sysfs_path, sysfs_data, strlen(sysfs_data));
    snprintf(sysfs_path, sizeof(sysfs_path), "/sys/class/disp/disp/attr/enhance_mode");
    snprintf(sysfs_data, sizeof(sysfs_data), "%d", enhance_mode);
    write_data(sysfs_path, sysfs_data, strlen(sysfs_data));
}

int main(int argc, char ** argv)
{
    printf("\n");
    printf("******************************************************************************************\n");
    printf("* This program implements a simple player, you can type commands to control the player.\n");
    printf("* To show what commands supported, type 'help'.\n");
    printf("******************************************************************************************\n");
    install_sig_handler();

    // clear fb0
    system("dd if=/dev/zero of=/dev/fb0");
//    set_enhance_mode();

    if(argc == 1) {
        printf("Please input file name\n");
        return -1;
    }
    system("amixer sset Headphone unmute");
    system("amixer sset \"Headphone volume\" 7");

    mTPlayer = TPlayerCreate(CEDARX_PLAYER);
    TPlayerSetDebugFlag(mTPlayer, false);
    if(mTPlayer == NULL) {
        printf("can not create tplayer, quit.\n");
        TPlayerDestroy(mTPlayer);
        return -1;
    }
    TPlayerSetNotifyCallback(mTPlayer, CallbackForTPlayer, (void *)NULL);
//    TPlayerSetScaleDownRatio(mTPlayer, TPLAYER_VIDEO_SCALE_DOWN_2, TPLAYER_VIDEO_SCALE_DOWN_2);
    //     TPlayerSetG2dRotate(mTPlayer, 1000);
    TPlayerSetDataSource(mTPlayer, argv[1], NULL);
    //    TPlayerSetVolume(mTPlayer, 100);

    TPlayerPrepare(mTPlayer);
    TPlayerStart(mTPlayer);

    char ch;
    while(!bQuit) {
        ch = getchar();
        switch(ch) {
            case 'l': {
                mSetLoop = !mSetLoop;
                printf("Looping: %d\n", mSetLoop);
                TPlayerSetLooping(mTPlayer, mSetLoop);
                break;
            }
            case 'q': {
                bQuit = 1;
                break;
            }
            case 'p': {
                if(TPlayerIsPlaying(mTPlayer)) {
                    TPlayerPause(mTPlayer);
                } else {
                    TPlayerStart(mTPlayer);
                }
                break;
            }
            case '/': {
                int volume = TPlayerGetVolume(mTPlayer);
                if((volume - 5) >= 0) {
                    volume -= 5;
                    TPlayerSetVolume(mTPlayer, volume);
                }
                printf("Volume %d\n", volume);
                break;
            }
            case '*': {
                int volume = TPlayerGetVolume(mTPlayer);
                if((volume + 5) <= 45) {
                    volume += 5;
                    TPlayerSetVolume(mTPlayer, volume);
                }
                printf("Volume %d\n", volume);
                break;
            }
            case 'f': {
                float realDispFramerate = 0.0f;
                TPlayerGetVideoDispFramerate(mTPlayer, &realDispFramerate);
                printf("FPS %.2f\n", realDispFramerate);
                break;
            }
            case 't': {
                int nPosition = 0;
                int nDuration = 0;

                if(TPlayerGetCurrentPosition(mTPlayer, &nPosition) == 0 &&
                   TPlayerGetDuration(mTPlayer, &nDuration) == 0) {
                    nPosition /= 1000;
                    nDuration /= 1000;
                    printf("current position = %02d:%02d/%02d:%02d.\n", nPosition / 60, nPosition % 60, nDuration / 60,
                           nDuration % 60);
                }
                break;
            }
            case 'w': {
                // SEEK 60
                int nPosition = 0;
                int nDuration = 0;
                TPlayerGetDuration(mTPlayer, &nDuration);
                TPlayerGetCurrentPosition(mTPlayer, &nPosition);
                nPosition = nPosition + 60 * 1000;
                if(nPosition < nDuration) {
                    TPlayerSeekTo(mTPlayer, nPosition);
                } else {
                    TPlayerSeekTo(mTPlayer, nDuration);
                }
                break;
            }
            case 's': {
                // SEEK -60
                int nPosition = 0;
                if(TPlayerGetCurrentPosition(mTPlayer, &nPosition) == 0) {
                    nPosition = nPosition - 60 * 1000;
                    if(nPosition > 0) {
                        TPlayerSeekTo(mTPlayer, nPosition);
                    } else {
                        TPlayerSeekTo(mTPlayer, 0);
                    }
                }
                break;
            }
            case 'a': {
                // SEEK 10
                int nPosition = 0;
                int nDuration = 0;
                TPlayerGetDuration(mTPlayer, &nDuration);
                TPlayerGetCurrentPosition(mTPlayer, &nPosition);
                nPosition = nPosition + 10 * 1000;
                if(nPosition < nDuration) {
                    TPlayerSeekTo(mTPlayer, nPosition);
                } else {
                    TPlayerSeekTo(mTPlayer, nDuration);
                }
                break;
            }
            case 'd': {
                // SEEK -10
                int nPosition = 0;
                if(TPlayerGetCurrentPosition(mTPlayer, &nPosition) == 0) {
                    nPosition = nPosition - 10 * 1000;
                    if(nPosition > 0) {
                        TPlayerSeekTo(mTPlayer, nPosition);
                    } else {
                        TPlayerSeekTo(mTPlayer, 0);
                    }
                }
                break;
            }
            case 'm': {
                mMediaInfo = TPlayerGetMediaInfo(mTPlayer);
                if(mMediaInfo != NULL) {
                    printf("file size = %lld KB\n", mMediaInfo->nFileSize / 1024);
                    printf("duration = %lld ms\n", mMediaInfo->nDurationMs);
                    printf("bitrate = %d Kbps\n", mMediaInfo->nBitrate / 1024);
                    printf("container type = %d\n", mMediaInfo->eContainerType);
                    printf("video stream num = %d\n", mMediaInfo->nVideoStreamNum);
                    printf("audio stream num = %d\n", mMediaInfo->nAudioStreamNum);
                    printf("subtitle stream num = %d\n", mMediaInfo->nSubtitleStreamNum);
                    if(mMediaInfo->pVideoStreamInfo != NULL) {
                        printf("video codec tpye = %d\n", mMediaInfo->pVideoStreamInfo->eCodecFormat);
                        printf("video width = %d\n", mMediaInfo->pVideoStreamInfo->nWidth);
                        printf("video height = %d\n", mMediaInfo->pVideoStreamInfo->nHeight);
                        printf("video framerate = %d\n", mMediaInfo->pVideoStreamInfo->nFrameRate);
                        printf("video frameduration = %d\n", mMediaInfo->pVideoStreamInfo->nFrameDuration);
                    }
                    if(mMediaInfo->pAudioStreamInfo != NULL) {
                        printf("audio codec tpye = %d\n", mMediaInfo->pAudioStreamInfo->eCodecFormat);
                        printf("audio channel num = %d\n", mMediaInfo->pAudioStreamInfo->nChannelNum);
                        printf("audio BitsPerSample = %d\n", mMediaInfo->pAudioStreamInfo->nBitsPerSample);
                        printf("audio sample rate  = %d\n", mMediaInfo->pAudioStreamInfo->nSampleRate);
                        printf("audio bitrate = %d Kbps\n", mMediaInfo->pAudioStreamInfo->nAvgBitrate / 1024);
                    }
                }
                break;
            }
        }
    }

    terminate(SIGINT);

    printf("\n");
    printf("******************************************************************************************\n");
    printf("* Quit the program, goodbye!\n");
    printf("******************************************************************************************\n");
    printf("\n");
    return 0;
}
